package com.my.study.barrier;

import com.my.study.utils.User;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;

/**
 * 测试Unsafe类
 *
 * 参考： https://developer.51cto.com/art/202104/660317.htm
 *
 * <p>
 *     1.内存操作
 *     2.内存屏障
 *     3.对象操作
 *     4.数组操作
 *     5.CAS操作
 *     6.线程调度
 *     7.Class操作
 *     8.系统信息
 * </p>
 *
 * <p>
 *     LoadLoad屏障：Load1;LoadLoad;Load2 => Load2及后续读取操作要读取的数据被访问前，保证Load1要读取的数据被读取完毕
 *     StoreStore屏障：Store1;StoreStore;Store2 => 在Store2及后续写入操作执行前，保证Store1的写入操作对其它处理器可见
 *     LoadStore屏障: Load1; LoadStore; Store2 => 在Store2及后续写入操作被刷出前，保证Load1要读取的数据被读取完毕
 *     StoreLoad屏障: Store1; StoreLoad; Load2 => 在Load2及后续所有读取操作执行前，保证Store1的写入对所有处理器可见。
 *                                               它的开销是四种屏障中最大的。在大多数处理器的实现中，这个屏障是个万能屏障，兼具其它三种内存屏障的功能。
 *     ----------------------------------------------------------------------------------------------------------------------------------------
 *     Load：将主内存中的数据拷贝到处理器的缓存中
 *     Store：将处理器缓存的数据刷新到主内存中
 * </p>
 *
 * @author: yidujun
 * @create: 2021/04/29 13:57
 */
@Slf4j(topic = "c.TestUnsafe")
public class TestUnsafe {

    private static final Unsafe unsafe = getUnsafe();
;
    public static void main(String[] args) throws Exception{
//        fieldTest();
//        objTest();
//        arrayTest();
//        casTest();
        parkTest();


    }

    private static void fieldTest() throws NoSuchFieldException {
        User user = new User();
        long fieldOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("userName"));
        log.debug("offset: {}", fieldOffset);
        unsafe.putObject(user, fieldOffset, "ydj");
        log.debug("userName: {}", user.getUserName());
        log.debug("userName: {}", unsafe.getObject(user, fieldOffset));
    }


    private static void objTest() throws IllegalAccessException, InstantiationException {
        Ab a1 = new Ab();
        log.debug("a1 {}", a1.getB());

        Ab a2 = Ab.class.newInstance();
        log.debug("a2 {}", a2.getB());

        Ab a3 = (Ab) unsafe.allocateInstance(Ab.class);
        log.debug("a3 {}", a3.getB());
    }

    /**
     * 数组操作
     */
    private static void arrayTest() {
        String[] arr1= new String[] {"str1str1str","str2","str3"};
        int baseOffset = unsafe.arrayBaseOffset(arr1.getClass());
        log.debug("arr1 baseOffset 对象.getClass() {}", baseOffset);
        log.debug("arr1 baseOffset 类.class {}", unsafe.arrayBaseOffset(String[].class));
        int scale = unsafe.arrayIndexScale(arr1.getClass());
        log.debug("scale {}", scale);

        for (int i = 0; i < arr1.length; i++) {
            int offset = baseOffset + scale * i;
            log.debug("{} : {}", offset, unsafe.getObject(arr1, offset));
        }
//        String[] arr2 = new String[] {"1", "2", "3", "4"};
//        log.debug("arr2 baseOffset 对象.getClass() {}", unsafe.arrayBaseOffset(arr2.getClass()));
//        log.debug("arr2 baseOffset 类.class {}", unsafe.arrayBaseOffset(String[].class));
    }

    private static void casTest() {
       final CasTest casTest = new CasTest();
       int a = casTest.a;
       new Thread(() -> {
           for (int i = 1; i < 5; i++) {
               casTest.increment(i);
               log.debug("{}", casTest.a);
           }
       }, "t1").start();

        new Thread(() -> {
            for (int i = 5; i < 10; i++) {
                casTest.increment(i);
                log.debug("{}", casTest.a);
            }
        }, "t2").start();
    }

    private static class CasTest {
        private volatile int a;

        public void  increment(int x) {
            while (true) {
                try {
                    long fieldOffset = unsafe.objectFieldOffset(CasTest.class.getDeclaredField("a"));
                    /*
                     * 比较并交换 成功就退出死循环
                     *
                     * 第一个参数：需要更新的对象
                     * 第二个参数：需要更新的对象中待操作属性的内存偏移量
                     * 第三个参数：期望值
                     * 第四个参数：新值
                     */
                    if (unsafe.compareAndSwapInt(this, fieldOffset, x - 1, x)) {
                        break;
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
            }

        }
    }


    private static void parkTest() {
        Thread mainThread = Thread.currentThread();

        // 开启一个子线程
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
                log.debug("sonThread try to unpark mainThread");
                unsafe.unpark(mainThread);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "sonThread").start();

        log.debug("park main mainThread");
        unsafe.park(false, 0L);
        log.debug("unpark main mainThread success");
    }

    /**
     * 利用反射 获取Unsafe实例
     * @return
     */
    private static Unsafe getUnsafe() {
        try {
            // 由于直接调用Unsafe.getUnsafe()需要配置JRE获取较高权限，我们利用反射获取Unsafe中的theUnsafe来取得Unsafe的可用实例。
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return ((Unsafe) field.get(null));
        } catch (Exception e) {
            log.error("获取Unsafe实例错误", e);
        }
        return null;
    }
}

@Data
class Ab {
    private int b;

    public Ab() {
        this.b = 1;
    }
}
